﻿#region File Header
/***********************************************************************
 * Copyright © 2013 Beals Software
 * All Rights Reserved
************************************************************************
Author: Donald Beals
Date: February 4th, 2013
Description: TODO: Write a description of this file here.
****************************** Change Log ******************************
02.04.13 - Created initial file. (dbeals)
02.18.13 - Added Username and UserToken. (dbeals)
***********************************************************************/
#endregion

#region Using Statements
using System;
using System.Linq;
using GameJolt.Async;
using GameJolt.Requests;
using Newtonsoft.Json;
#endregion

namespace GameJolt
{
	/// <summary>
	/// 
	/// </summary>
	[JsonObject]
	public sealed class DataStore
	{
		#region Properties
		[JsonIgnore]
		public DataStoreType Type
		{
			get;
			set;
		}

		[JsonProperty("key")]
		public string Key
		{
			get;
			set;
		}

		public string Data
		{
			get;
			set;
		}

		public string Username
		{
			get;
			set;
		}

		public string UserToken
		{
			get;
			set;
		}
		#endregion

		#region Constructors
		public DataStore()
		{
		}

		public DataStore(DataStoreType type, string key, string data, string username, string userToken)
		{
			this.Type = type;
			this.Key = key;
			this.Data = data;
			this.Username = username;
			this.UserToken = userToken;
		}
		#endregion

		#region Methods
		public override string ToString()
		{
			return string.Format("Type={0},Key={1},Data={2}", Type, Key, Data);
		}

		public static IAsyncResult BeginGetKeys(string gameID, string privateKey, string username, string userToken, DataStoreType type, AsyncCallback callback = null, object asyncState = null)
		{
			var request = DataStoreRequestFactory.CreateGetRequest(gameID, privateKey, username, userToken, type);
			return request.Begin(callback, asyncState);
		}

		public static string[] EndGetKeys(IAsyncResult result)
		{
			var joltResult = (AsyncResult<string[]>)result;
			var request = (JsonRequest<DataStore[], DataStoreRequestFactory.DataStoreKeysResult>)joltResult.CoreData;
			var keys = request.End(result);
			if(keys == null)
				return null;
			return (from key in keys
					select key.Key).ToArray();
		}

		public static string[] GetKeys(string gameID, string privateKey, string username, string userToken, DataStoreType type)
		{
			var request = DataStoreRequestFactory.CreateGetRequest(gameID, privateKey, username, userToken, type);
			var keys = request.Process(null);

			if(keys == null)
				return null;
			return (from key in keys
					select key.Key).ToArray();
		}

		public static IAsyncResult GetKeys(string gameID, string privateKey, string username, string userToken, DataStoreType type, Action<string[]> callback)
		{
			return BeginGetKeys(gameID, privateKey, username, userToken, type, (result) => callback(EndGetKeys(result)));
		}

		public static IAsyncResult BeginGetByKey(string gameID, string privateKey, string username, string userToken, string key, AsyncCallback callback = null, object asyncState = null)
		{
			var request = DataStoreRequestFactory.CreateGetRequest(gameID, privateKey, username, userToken, key);
			return request.Begin(callback, asyncState);
		}

		public static DataStore EndGetByKey(IAsyncResult result)
		{
			var joltResult = (AsyncResult<string>)result;
			var request = (DumpRequest)joltResult.CoreData;
			var data = request.End(result);

			if(!request.WasSuccessful)
				throw new Exception(data);

			bool isGame = request.Parameters.Contains(RequestParameter.UsernameKey);
			return new DataStore(isGame ? DataStoreType.Game : DataStoreType.User, (string)request.Parameters[RequestParameter.KeyKey], data, (string )request.Parameters[RequestParameter.UsernameKey], (string)request.Parameters[RequestParameter.UserTokenKey]);
		}

		public static DataStore GetByKey(string gameID, string privateKey, string username, string userToken, string key)
		{
			var request = DataStoreRequestFactory.CreateGetRequest(gameID, privateKey, username, userToken, key);
			var data = request.Process(null);
			if(!request.WasSuccessful)
			{
				Logging.LogWarning(data);
				return null;
			}

			bool isGame = string.IsNullOrWhiteSpace(username);
			return new DataStore(isGame ? DataStoreType.Game : DataStoreType.User, key, data, username, userToken);
		}

		public static IAsyncResult GetByKey(string gameID, string privateKey, string username, string userToken, string key, Action<DataStore> callback)
		{
			return BeginGetByKey(gameID, privateKey, username, userToken, key, (result) => callback(EndGetByKey(result)));
		}

		public static IAsyncResult BeginSetByKey(string gameID, string privateKey, string username, string userToken, string key, string data, AsyncCallback callback = null, object asyncState = null)
		{
			var request = DataStoreRequestFactory.CreateSetRequest(gameID, privateKey, username, userToken, key, data);
			return request.Begin(callback, asyncState);
		}

		public static string EndSetByKey(IAsyncResult result)
		{
			var joltResult = (AsyncResult<string>)result;
			var request = (StringRequest)joltResult.CoreData;
			return request.End(result);
		}

		public static string SetByKey(string gameID, string privateKey, string username, string userToken, string key, string data)
		{
			var request = DataStoreRequestFactory.CreateSetRequest(gameID, privateKey, username, userToken, key, data);
			return request.Process(null);
		}

		public static IAsyncResult SetByKey(string gameID, string privateKey, string username, string userToken, string key, string data, Action<string> callback)
		{
			return BeginSetByKey(gameID, privateKey, username, userToken, key, data, (result) => callback(EndSetByKey(result)));
		}

		public static IAsyncResult BeginUpdateByKey(string gameID, string privateKey, string username, string userToken, string key, DataStoreOperation operation, string value, AsyncCallback callback = null, object asyncState = null)
		{
			var request = DataStoreRequestFactory.CreateUpdateRequest(gameID, privateKey, username, userToken, key, operation, value);
			return request.Begin(callback, asyncState);
		}

		public static DataStore EndUpdateByKey(IAsyncResult result)
		{
			var joltResult = (AsyncResult<string>)result;
			var request = (DumpRequest)joltResult.CoreData;
			var data = request.End(result);

			if(!request.WasSuccessful)
				throw new Exception(data);
			bool isGame = request.Parameters.Contains(RequestParameter.UsernameKey);
			return new DataStore(isGame ? DataStoreType.Game : DataStoreType.User, (string)request.Parameters[RequestParameter.KeyKey], data, (string)request.Parameters[RequestParameter.UsernameKey], (string)request.Parameters[RequestParameter.UserTokenKey]);
		}

		public static DataStore UpdateByKey(string gameID, string privateKey, string username, string userToken, string key, DataStoreOperation operation, string value)
		{
			var request = DataStoreRequestFactory.CreateUpdateRequest(gameID, privateKey, username, userToken, key, operation, value);
			var data = request.Process(null);
			bool isGame = string.IsNullOrWhiteSpace(username);
			return new DataStore(isGame ? DataStoreType.Game : DataStoreType.User, key, data, username, userToken);
		}

		public static IAsyncResult UpdateByKey(string gameID, string privateKey, string username, string userToken, string key, DataStoreOperation operation, string value, Action<DataStore> callback)
		{
			return BeginUpdateByKey(gameID, privateKey, username, userToken, key, operation, value, (result) => callback(EndUpdateByKey(result)));
		}

		public static IAsyncResult BeginRemoveByKey(string gameID, string privateKey, string username, string userToken, string key, AsyncCallback callback = null, object asyncState = null)
		{
			var request = DataStoreRequestFactory.CreateRemoveRequest(gameID, privateKey, username, userToken, key);
			return request.Begin(callback, asyncState);
		}

		public static string EndRemoveByKey(IAsyncResult result)
		{
			var joltResult = (AsyncResult<string>)result;
			var request = (StringRequest)joltResult.CoreData;
			return request.End(result);
		}

		public static string RemoveByKey(string gameID, string privateKey, string username, string userToken, string key)
		{
			var request = DataStoreRequestFactory.CreateRemoveRequest(gameID, privateKey, username, userToken, key);
			return request.Process(null);
		}

		public static IAsyncResult RemoveByKey(string gameID, string privateKey, string username, string userToken, string key, Action<string> callback)
		{
			return BeginRemoveByKey(gameID, privateKey, username, userToken, key, (result) => callback(EndRemoveByKey(result)));
		}

		public static bool GameDataStoreExists(string gameID, string privateKey, string dataStoreKey)
		{
			var keys = GameJolt.DataStore.GetKeys(gameID, privateKey, null, null, GameJolt.DataStoreType.Game);
			if(keys == null || keys.Length == 0)
				return false;

			return keys.Contains(dataStoreKey);
		}

		public static bool UserDataStoreExists(string gameID, string privateKey, string username, string userToken, string dataStoreKey)
		{
			var keys = GameJolt.DataStore.GetKeys(gameID, privateKey, username, userToken, GameJolt.DataStoreType.User);
			if(keys == null || keys.Length == 0)
				return false;

			return keys.Contains(dataStoreKey);
		}
		#endregion
	}
}
